package com.societyGames.flashForms
{
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;

public class ScrollContainer extends SingleItemContainer
{
  private var _horizontalTrack:Sprite;
  private var _horizontalThumb:Sprite;
  private var _horizontalDraggable:Draggable;
  private var _verticalTrack:Sprite;
  private var _verticalThumb:Sprite;
  private var _verticalDraggable:Draggable;
  private var _desiredWidth:Number;
  private var _desiredHeight:Number;
  private var _visibleRectangle:Rectangle = new Rectangle();
  private var _horizontalVisible:Boolean;
  private var _verticalVisible:Boolean;
  private var _availableWidth:Number;
  private var _availableHeight:Number;
  private var _scrollRectSprite:Sprite = new Sprite(); //A special sprite for applying the scroll rect.
  private var _horizontalPercent:Number; //What percent to the right are we showing?
  private var _verticalPercent:Number;  //What percent to the bottom are we showing?
  private var _pixelsPerScrollClick:Number = 10; //How many pixels do we want to move per click?

  public function ScrollContainer(horizontalTrack:Sprite, horizontalThumb:Sprite, verticalTrack:Sprite, verticalThumb:Sprite)
  {
    this.mouseEnabled = true;
    this.mouseChildren = true;

    this._horizontalTrack = horizontalTrack;
    this._horizontalThumb = horizontalThumb;
    this._horizontalDraggable = new Draggable(this._horizontalThumb, new Rectangle());
    this._horizontalDraggable.movedEventObject.addEventListener(horizontalMovedHandler);
    this._horizontalDraggable.droppedEventObject.addEventListener(horizontalDroppedHandler);

    this._verticalTrack = verticalTrack;
    this._verticalThumb = verticalThumb;
    this._verticalDraggable = new Draggable(this._verticalThumb, new Rectangle());
    this._verticalDraggable.movedEventObject.addEventListener(verticalMovedHandler);
    this._verticalDraggable.droppedEventObject.addEventListener(verticalDroppedHandler);

    this.addEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
    this.addEventListener(MouseEvent.ROLL_OUT, rollOutHandler);

    this.addChild(this._scrollRectSprite);
    this.addChild(this._horizontalTrack);
    this.addChild(this._verticalTrack);
    this.addChild(this._horizontalThumb);
    this.addChild(this._verticalThumb);
    zeroThumbPositions();
  }

  public override function set width(value:Number):void
  {
    if (value != this._desiredWidth)
    {
      this._desiredWidth = value;
      calculateProportions();
    }
  }

  public override function set height(value:Number):void
  {
    if (value != this._desiredHeight)
    {
      this._desiredHeight = value;
      calculateProportions();
    }
  }

  public function set pixelsPerScrollClick(value:Number):void
  {
    if (value < 0 || isNaN(value))
    {
      value = 0;
    }
    this._pixelsPerScrollClick = value;
  }

  public function get pixelsPerScrollClick():Number
  {
    return this._pixelsPerScrollClick;
  }

  public override function set item(value:DisplayObject):void
  {
    if (this._item != value)
    {
      var changeSize:IChangeSize;
      //Remove the old one.
      if (this._item != null)
      {
        changeSize = this._item as IChangeSize;
        if (changeSize != null)
        {
          changeSize.sizeChangedEventObject.removeEventListener(childSizeChangedHandler);
        }
        this._scrollRectSprite.removeChild(this._item);
      }
      this._item = value;
      //Deal with the new one.
      if (this._item != null)
      {
        changeSize = this._item as IChangeSize;
        if (changeSize != null)
        {
          changeSize.sizeChangedEventObject.addEventListener(childSizeChangedHandler);
        }
        this._scrollRectSprite.addChild(this._item);
      }
      childSizeChangedHandler(null);
    }
  }

  public function get verticalTrackWidth():Number
  {
    return this._verticalTrack.width;
  }

  public function get horizontalTrackHeight():Number
  {
    return this._horizontalTrack.height;
  }

  protected override function childSizeChangedHandler(event:Event):void
  {
    this.calculateProportions();
  }

  private function zeroThumbPositions():void
  {
    this._horizontalThumb.x = 0;
    this._verticalThumb.y = 0;
  }

  private function calculateFromThumbPositions():void
  {
    this._visibleRectangle.x = 0;
    if (_horizontalVisible)
    {
      this._horizontalPercent = (this._horizontalThumb.x / (_availableWidth - this._horizontalThumb.width));
      this._visibleRectangle.x = this._horizontalPercent * (this._item.width - _availableWidth);
    }
    this._visibleRectangle.y = 0;
    if (_verticalVisible)
    {
      this._verticalPercent = (this._verticalThumb.y / (_availableHeight - this._verticalThumb.height));
      this._visibleRectangle.y = this._verticalPercent * (this._item.height - _availableHeight);
    }
    this._scrollRectSprite.scrollRect = this._visibleRectangle;
  }

  private function calculateProportions():void
  {
    if (this._item != null)
    {
      _horizontalVisible = this._item.width > this._desiredWidth;
      _verticalVisible = this._item.height > this._desiredHeight;
      if (_verticalVisible)
      {
        _horizontalVisible = this._item.width > (this._desiredWidth - this._verticalTrack.width);
      }
      if (_horizontalVisible)
      {
        _verticalVisible = this._item.height > (this._desiredHeight - this._horizontalTrack.height);
      }

      this._horizontalTrack.visible = this._horizontalThumb.visible = _horizontalVisible;
      this._verticalTrack.visible = this._verticalThumb.visible = _verticalVisible;

      _availableWidth = _verticalVisible ? this._desiredWidth - this._verticalTrack.width : this._desiredWidth;
      _availableHeight = _horizontalVisible ? this._desiredHeight - this._horizontalTrack.height : this._desiredHeight;

      this._visibleRectangle.width = _availableWidth;
      this._visibleRectangle.height = _availableHeight;

      if (_horizontalVisible)
      {
        this._horizontalTrack.y = this._desiredHeight - this._horizontalTrack.height;
        this._horizontalTrack.width = _availableWidth;
        this._horizontalThumb.width = _availableWidth * (_availableWidth / this._item.width);
        this._horizontalThumb.x = Math.round(this._horizontalPercent * (_availableWidth - this._horizontalThumb.width));
        this._horizontalThumb.y = Math.round(this._desiredHeight - this._horizontalThumb.height);
        this._horizontalDraggable.bounds.x = 0;
        this._horizontalDraggable.bounds.y = Math.round(this._horizontalTrack.y);
        this._horizontalDraggable.bounds.width = Math.round(_availableWidth - this._horizontalThumb.width);
        this._horizontalDraggable.bounds.height = 0;
      }

      if (_verticalVisible)
      {
        this._verticalTrack.x = this._desiredWidth - this._verticalTrack.width;
        this._verticalTrack.height = _availableHeight;
        this._verticalThumb.height = _availableHeight * (_availableHeight / this._item.height);
        this._verticalThumb.x = Math.round(this._desiredWidth - this._verticalThumb.width);
        this._verticalThumb.y = Math.round(this._verticalPercent * (_availableHeight - this._verticalThumb.height));
        this._verticalDraggable.bounds.x = Math.round(this._verticalTrack.x);
        this._verticalDraggable.bounds.y = 0;
        this._verticalDraggable.bounds.width = 0;
        this._verticalDraggable.bounds.height = Math.round(_availableHeight - this._verticalThumb.height);
      }
      calculateFromThumbPositions();
    }
    else
    {
      this._horizontalTrack.visible = this._horizontalThumb.visible = _horizontalVisible = false;
      this._verticalTrack.visible = this._verticalThumb.visible = _verticalVisible = false;
    }
  }

  private function horizontalMovedHandler(event:Event):void
  {
    this.calculateFromThumbPositions();
  }

  private function horizontalDroppedHandler(event:Event):void
  {
    this.calculateFromThumbPositions();
  }

  private function verticalMovedHandler(event:Event):void
  {
    this.calculateFromThumbPositions();
  }

  private function verticalDroppedHandler(event:Event):void
  {
    this.calculateFromThumbPositions();
  }

  private function rollOverHandler(event:MouseEvent):void
  {
    this.addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler);
  }

  private function rollOutHandler(event:MouseEvent):void
  {
    this.removeEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler);
  }

  private function mouseWheelHandler(event:MouseEvent):void
  {
    if (this._verticalTrack.visible)
    {
      //Calculate what percent in item space we're moving.
      var pixelsItemSpace:Number = this._pixelsPerScrollClick * -event.delta;
      if (this._item != null && ((this._item.height - _availableHeight) != 0))
      {
        var percent:Number = pixelsItemSpace / (this._item.height - _availableHeight);
        //Now move the thumb in scroll bar space.
        this._verticalThumb.y += percent * (_availableHeight - this._verticalThumb.height);
        if (this._verticalThumb.y < 0)
        {
          this._verticalThumb.y = 0;
        }
        else if (this._verticalThumb.y >= this._verticalDraggable.bounds.height)
        {
          this._verticalThumb.y = this._verticalDraggable.bounds.height - 1;
        }
        this.calculateFromThumbPositions();
      }
    }
  }
}
}